<?php
/**
 * Module: Ignore
 * 
 * This module allows the bot owner(s) to ignore people who are
 * abusing the bot. The owner(s) can not be ignored, no matter
 * what happens. The ignorelist is automatically saved and loaded
 * between bot starts.
 * 
 * It is recommended to add this module to the PriorityQueue in
 * config.php for best results.
 * 
 * Author: MrBondt
 *         mrbondt@goldenak.eu
 */

class Ignore extends ModuleBase {
	
	/**
	 * Property: m_aIgnored
	 * 
	 * This array contains all the patterns to ignore. These
	 * are matched against the usermasks of incoming messages.
	 */
	private $m_aIgnored;
	
	/**
	 * Function: __construct
	 * 
	 * The constructor will load up all the ignored people.
	 */
	public function __construct () {
		$this -> loadIgnored ();
	}
	
	/**
	 * Function: __destruct
	 * 
	 * The destructor will quickly save everything before 
	 * the bot shuts down.
	 */
	public function __destruct () {
		//$this -> saveIgnored ();
	}
	
	/**
	 * Function: loadIgnored
	 * 
	 * This method loads all the ignored patterns from Ignore.dat.
	 */
	public function loadIgnored () {
		if (file_exists ('Data/Ignore.dat')) {
			$this -> m_aIgnored = unserialize (file_get_contents ('Data/Ignore.dat'));
		} else {
			$this -> m_aIgnored = array ();
		}
	}
	
	/**
	 * Function: saveIgnored
	 * 
	 * This method saves all ignored patterns to Ignore.dat.
	 */
	public function saveIgnored () {
		file_put_contents ('Data/Ignore.dat', serialize ($this -> m_aIgnored));
	}
	
	/**
	 * Function: addIgnore
	 * Argument: sIgnore (string) - The pattern to ignore
	 * 
	 * This method will add the given pattern to the array
	 * with all ignored patterns.
	 */
	private function addIgnore ($sIgnore) {
		if ($this -> isIgnored ($sIgnore)) {
			return false;
		}
		$this -> m_aIgnored [] = $sIgnore;
		
		return true;
	}
	
	/**
	 * Function: removeIgnore
	 * Argument: sIgnore (string) - The pattern to remove
	 * 
	 * Removes the given pattern from the ignored list.
	 */
	private function removeIgnore ($sIgnore) {
		if (!$this -> isIgnored ($sIgnore)) {
			return false;
		}
		unset ($this -> m_aIgnored [array_search ($sIgnore, $this -> m_aIgnored)]);
		
		return true;
	}
	
	/**
	 * Function: isIgnored
	 * Argument: sIgnore (string) - The pattern to check
	 * 
	 * Checks if the given pattern is ignored.
	 */
	private function isIgnored ($sIgnore) {
		return in_array ($sIgnore, $this -> m_aIgnored);
	}
	
	/**
	 * Function: getIgnored
	 * 
	 * This method returns the list of all ignored patterns.
	 */
	public function getIgnored () {
		return $this -> m_aIgnored;
	}
	
	/**
	 * Function: isBotOwner
	 * Argument: pBot (Bot) - The bot with the received message.
	 * 
	 * This method takes a Bot instance, and checks with the Evaluation
	 * module if the current message being processed, is our owner.
	 */
	public function isBotOwner (Bot $pBot) {
		$pEval = ModuleManager :: getInstance () -> offsetGet ('Evaluation');
		if ($pEval -> checkSecurity ($pBot, 9999)) {
			return true;
		}
		return false;
	}
	
	/**
	 * Function: checkIgnore
	 * Argument: sMask (string) - The mask to match against
	 * 
	 * This method loops through all ignored patterns and tries
	 * to match the given mask against every one of them, until
	 * a match is found. This method could be extended in the 
	 * future with more advanced matching techniques.
	 */
	private function checkIgnore ($sMask) {
		foreach ($this -> m_aIgnored as $sIgnore) {
			if (stripos ($sMask, $sIgnore) !== false) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Function: handleCommand
	 * Argument: pBot (Bot) - The current bot
	 * Argument: sMessage (string) - The message containing a command (or not)
	 * Argument: sDest (string) - The destination to send the messages to
	 * 
	 * This method returns true when a command has properly
	 * been handled, false when nothing has been done, and
	 * ModuleManager :: FINISHED when the message should be
	 * ignored.
	 */
	private function handleCommand (Bot $pBot, $sMessage, $sDest) {
		if (!$this -> isBotOwner ($pBot)) {
			// Can't ignore the bot owner, that would fuck things up.
			$sMask = $pBot -> In -> User;
			if ($this -> checkIgnore ($sMask)) {
				return ModuleManager :: FINISHED;
			} else {
				return true;
			}
		} else {
			// Commands for the bot owner.
			if (strpos ($sMessage, ' ') === false) {
				$sTrigger = $sMessage;
				$sParams = null;
			} else {
				list ($sTrigger, $sParams) = explode (' ', $sMessage, 2);
				$sParams = trim ($sParams);
			}
			
			switch ($sTrigger) {
				case '!ignore':
					if ($sParams == null) {
						$sMsg = '3Usage: !ignore Pattern';
					} else {
						if ($this -> addIgnore ($sParams)) {
							$sMsg = '3Success: *' . $sParams . '* is now ignored.';
							$this -> saveIgnored ();
						} else {
							$sMsg = '4Error: *' . $sParams . '* is already ignored.';
						}
					}
					break;
					
				case '!unignore':
					if ($sParams == null) {
						$sMsg = '3Usage: !unignore Pattern';
					} else {
						if ($this -> removeIgnore ($sParams)) {
							$sMsg = '3Success: *' . $sParams . '* is not ignored anymore.';
							$this -> saveIgnored ();
						} else {
							$sMsg = '4Error: *' . $sParams . '* is not ignored.';
						}
					}
					break;
					
				case '!ignored':
					$sMsg = '3Ignored: ';
					
					foreach ($this -> getIgnored () as $sIgnore) {
						$sMsg .= '*' . $sIgnore . '*, ';
					}
					if (strlen ($sMsg) > 12) {
						$sMsg = substr ($sMsg, 0, -2);
					} else {
						$sMsg .= '14None';
					}
					break;
			}
		}
		
		if (isset ($sMsg)) {
			$pBot -> send ('PRIVMSG ' . $sDest . ' :' . $sMsg);
			return true;
		}
		
		return false;
	}
	
	/**
	 * Function: onChannelPrivmsg
	 * Argument: pBot (Bot) - The bot which received this message.
	 * Argument: sChannel (string) - The channel this message was spammed in
	 * Argument: sNickname (string) - Nickname who is messaging us (or the channel).
	 * Argument: sMessage (string) - The message being send to us.
	 *
	 * This method allows us to ignore channel PRIVMSGs from the ignored users.
	 */
	public function onChannelPrivmsg (Bot $pBot, $sChannel, $sNickname, $sMessage) {
		return $this -> handleCommand ($pBot, $sMessage, $sChannel);
	}
	
	/**
	 * Function: onNotice
	 * Argument: pBot (Bot) - The bot which received this message.
	 * Argument: sChannel (string) - The channel this message was spammed in
	 * Argument: sNickname (string) - Nickname who is messaging us (or the channel).
	 * Argument: sMessage (string) - The message being send to us.
	 * 
	 * We will also ignore notices, because those can used to provide commands
	 * to the bot as well.
	 */
	public function onNotice (Bot $pBot, $sChannel, $sNickname, $sMessage) {
		return $this -> handleCommand ($pBot, $sMessage, $sNickname);
	}
	
	/**
	 * Function: onPrivmsg
	 * Argument: pBot (Bot) - The bot which received this message.
	 * Argument: sNickname (string) - Nickname who is PM'ing us.
	 * Argument: sMessage (string) - The message being send to us.
	 * 
	 * Well, queries should be ignored as well.
	 */
	public function onPrivmsg (Bot $pBot, $sNickname, $sMessage) {
		return $this -> handleCommand ($pBot, $sMessage, $sNickname);
	}
}
?>